using System.Collections.Generic;
using System.Threading;

//
// * Copyright (c) 2002-2009 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
namespace org.neo4j.kernel.impl.event
{


	using Test = junit.framework.Test;
	using TestCase = junit.framework.TestCase;
	using TestSuite = junit.framework.TestSuite;

	using Event = org.neo4j.kernel.impl.event.Event;
	using EventData = org.neo4j.kernel.impl.event.EventData;
	using EventListenerAlreadyRegisteredException = org.neo4j.kernel.impl.event.EventListenerAlreadyRegisteredException;
	using EventListenerNotRegisteredException = org.neo4j.kernel.impl.event.EventListenerNotRegisteredException;
	using EventManager = org.neo4j.kernel.impl.event.EventManager;
	using EventModule = org.neo4j.kernel.impl.event.EventModule;
	using ProActiveEventListener = org.neo4j.kernel.impl.event.ProActiveEventListener;
	using ReActiveEventListener = org.neo4j.kernel.impl.event.ReActiveEventListener;

	public class TestEventManager : TestCase
	{
		private EventManager evtMgr;
		private EventModule module = new EventModule();

		public virtual void setUp()
		{
			module.init();
			module.Start();
			evtMgr = module.getEventManager();
		}

		public virtual void tearDown()
		{
			module.Stop();
			module.destroy();
		}

		private class MyProActiveEventListener : ProActiveEventListener
		{
			private bool state = true;

			public virtual bool proActiveEventReceived(Event @event, EventData data)
			{
				return state;
			}

			internal virtual void setState(bool mode)
			{
				state = mode;
			}
		}

		private class MyReActiveEventListener : ReActiveEventListener
		{
			private bool eventReceived = false;
			private Thread originatingThread = null;

			public virtual void reActiveEventReceived(Event @event, EventData data)
			{
				this.eventReceived = true;
				this.originatingThread = data.getOriginatingThread();
			}

			internal virtual void reset()
			{
				this.eventReceived = false;
				this.originatingThread = null;
			}

			internal virtual bool isEventReceived()
			{
				return this.eventReceived;
			}

			internal virtual Thread getOriginatingThread()
			{
				return this.originatingThread;
			}
		}

		public TestEventManager(string testName) : base(testName)
		{
		}

		public static Test suite()
		{
			return new TestSuite(typeof(TestEventManager));
		}

//JAVA TO VB & C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public void testProActiveEventListener() throws EventListenerAlreadyRegisteredException, EventListenerNotRegisteredException
		public virtual void testProActiveEventListener()
		{
		// register test
			try
			{
				evtMgr.registerProActiveEventListener(null, Event.TEST_EVENT);
				fail("null listener should throw exception.");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			MyProActiveEventListener myEvtListener1 = new MyProActiveEventListener();
			try
			{
				evtMgr.registerProActiveEventListener(myEvtListener1, null);
				fail("null event should throw exception.");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			evtMgr.registerProActiveEventListener(myEvtListener1, Event.TEST_EVENT);
			try
			{
				evtMgr.registerProActiveEventListener(myEvtListener1, Event.TEST_EVENT);
				fail("registration of same listener, should throw exception. ");
			}
			catch (EventListenerAlreadyRegisteredException e)
			{
			}

		// unregister test
			MyProActiveEventListener myEvtListener2 = new MyProActiveEventListener();
			MyProActiveEventListener myEvtListener3 = new MyProActiveEventListener();
			evtMgr.registerProActiveEventListener(myEvtListener2, Event.TEST_EVENT);
			evtMgr.registerProActiveEventListener(myEvtListener3, Event.TEST_EVENT);
			evtMgr.unregisterProActiveEventListener(myEvtListener3, Event.TEST_EVENT);
			try
			{
				evtMgr.unregisterProActiveEventListener(myEvtListener3, Event.TEST_EVENT);
				fail("unregister of non registered listener " + "should throw exception");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			evtMgr.registerProActiveEventListener(myEvtListener3, Event.TEST_EVENT);

		// send test
			assertTrue(evtMgr.generateProActiveEvent(Event.TEST_EVENT, new EventData(null)));
			myEvtListener3.setState(false);
			assertTrue(!evtMgr.generateProActiveEvent(Event.TEST_EVENT, new EventData(null)));
			myEvtListener2.setState(false);
			myEvtListener3.setState(true);
			assertTrue(!evtMgr.generateProActiveEvent(Event.TEST_EVENT, new EventData(null)));
			myEvtListener2.setState(true);
			assertTrue(evtMgr.generateProActiveEvent(Event.TEST_EVENT, new EventData(null)));
			evtMgr.unregisterProActiveEventListener(myEvtListener1, Event.TEST_EVENT);
			evtMgr.unregisterProActiveEventListener(myEvtListener2, Event.TEST_EVENT);
			evtMgr.unregisterProActiveEventListener(myEvtListener3, Event.TEST_EVENT);
			assertTrue(evtMgr.generateProActiveEvent(Event.TEST_EVENT, new EventData(null)));
		}

//JAVA TO VB & C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public void testReActiveEventListener() throws EventListenerAlreadyRegisteredException, EventListenerNotRegisteredException
		public virtual void testReActiveEventListener()
		{
		// register test
			try
			{
				evtMgr.registerReActiveEventListener(null, Event.TEST_EVENT);
				fail("null listener should throw exception.");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			MyReActiveEventListener myEvtListener1 = new MyReActiveEventListener();
			try
			{
				evtMgr.registerReActiveEventListener(myEvtListener1, null);
				fail("null event should throw exception.");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			evtMgr.registerReActiveEventListener(myEvtListener1, Event.TEST_EVENT);
			try
			{
				evtMgr.registerReActiveEventListener(myEvtListener1, Event.TEST_EVENT);
				fail("registration of same listener, should throw exception. ");
			}
			catch (EventListenerAlreadyRegisteredException e)
			{
			}

		// unregister test
			MyReActiveEventListener myEvtListener2 = new MyReActiveEventListener();
			MyReActiveEventListener myEvtListener3 = new MyReActiveEventListener();
			evtMgr.registerReActiveEventListener(myEvtListener2, Event.TEST_EVENT);
			evtMgr.registerReActiveEventListener(myEvtListener3, Event.TEST_EVENT);
			evtMgr.unregisterReActiveEventListener(myEvtListener3, Event.TEST_EVENT);
			try
			{
				evtMgr.unregisterReActiveEventListener(myEvtListener3, Event.TEST_EVENT);
				fail("unregister of non registered listener " + "should throw exception");
			}
			catch (EventListenerNotRegisteredException e)
			{
			}
			evtMgr.registerReActiveEventListener(myEvtListener3, Event.TEST_EVENT);

		// send test
			evtMgr.generateReActiveEvent(Event.TEST_EVENT, new EventData(null));
			waitForReceived(new MyReActiveEventListener[] { myEvtListener1, myEvtListener2, myEvtListener3 });
			evtMgr.unregisterReActiveEventListener(myEvtListener1, Event.TEST_EVENT);
			evtMgr.unregisterReActiveEventListener(myEvtListener2, Event.TEST_EVENT);
			evtMgr.unregisterReActiveEventListener(myEvtListener3, Event.TEST_EVENT);
		}

		public virtual void testStartStopEventManager()
		{
			module.Stop();
			module.Start();
		}

		private void waitForReceived(MyReActiveEventListener[] listeners)
		{
			List<MyReActiveEventListener> listenerList = new List<MyReActiveEventListener>();
			for (int i = 0; i < listeners.Length; i++)
			{
				listenerList.Add(listeners[i]);
			}
			int iterations = 0;
			while (listenerList.Count > 0 && iterations < 10)
			{
				for (int i = 0; i < listenerList.Count; i++)
				{
					MyReActiveEventListener myListener = listenerList[i];
					if (myListener.isEventReceived())
					{
						listenerList.Remove(i);
						if (listenerList.Count == 0)
						{
							return;
						}
					}
				}

				try
				{
					Thread.Sleep(100);
				}
				catch (InterruptedException ie)
				{
				}
				iterations++;
			}
			fail("Reactive events not received.");
		}

		public virtual void testEventData()
		{
			object data = new object();
			EventData eventData = new EventData(data);
			assertTrue(eventData.getData() == data);
		}

		public virtual void testReActiveEventOriginatingThread()
		{
			try
			{
				MyReActiveEventListener listener = new MyReActiveEventListener();
				evtMgr.registerReActiveEventListener(listener, Event.TEST_EVENT);
				evtMgr.generateReActiveEvent(Event.TEST_EVENT, new EventData(null));
				waitForReceived(new MyReActiveEventListener[] { listener });
				assertEquals("Wrong originating thread for event", Thread.CurrentThread, listener.getOriginatingThread());
			}
			catch (Exception e)
			{
				fail("Unknown exception: " + e);
			}
		}
	}
}